package com.hm.cdz.trace;

import java.util.ArrayList;
import java.util.List;

import com.hm.common.conversion.U16;

import lombok.Data;

/**
 * @author shishun.wang
 * @date 2018年5月7日 下午3:48:58
 * @version 1.0
 * @describe
 */
public class MainApp {

	public static void main(String[] args) throws Exception {

		String str = "5353 1F00 75 01088A291B890B28000002010103063030303030306F0100 A5 45";

		byte[] bys = toBytes(str);

		// byte[] stx = subBytes(bys, 0, 2);
		// byte[] etx = subBytes(bys, bys.length - 1, 1);
		// byte[] instruction = subBytes(bys, 2, 2);
		// byte[] checksum = subBytes(bys, bys.length - 2, 1);
		// byte[] body = subBytes(bys, 5, bys.length - 7);

		// DataFormat format = new DataFormat(stx, instruction, length, param, checksum,
		// etx);
		// System.out.println("stx==>" + new
		// U16(bytesToHexFun2(format.getStx())).toAscii());
		// System.out.println("etx==>" + new
		// U16(bytesToHexFun2(format.getEtx())).toAscii());
		// System.out.println("instruction==>" + new
		// U16(bytesToHexFun2(format.getInstruction())).toU10());
		// System.out.println("checksum==>" + new
		// U16(bytesToHexFun2(format.getChecksum())).toU10());

		DataFormat format = new DataFormat(bys);
		print(format);
	}
	
	public static void print2(DataFormat format) {
		System.out.println("###########################################");
		System.out.println("STX:" + bytesToHexFun2(format.getStx()));
		System.out.println("长度:" + bytesToHexFun2(format.getLength()));
		System.out.println("指令编号:" + bytesToHexFun2(format.getInstruction()));
		System.out.println("CHECKSUM:" + bytesToHexFun2(format.getChecksum()));
		System.out.println("ETX:" + bytesToHexFun2(format.getEtx()));

		for (Param p : parsing(format.getBody(), new ArrayList<Param>())) {
			System.out.println("参数序号:" + new U16(bytesToHexFun2(p.getParamNum())).toU10());
			System.out.println("参数长度:" + new U16(bytesToHexFun2(p.getParamLenth())).toU10());
			System.out.println("参数值:" + bytesToHexFun2(p.getParamValue()));
			System.out.println("------------------------------------------");
		}
		System.out.println("###########################################");
	}

	public static void print(DataFormat format) {
		System.out.println("###########################################");
		System.out.println("STX:" + new U16(bytesToHexFun2(format.getStx())).toAscii());
		System.out.println("长度:" + new U16(bytesToHexFun2(format.getLength())).toU10());
		System.out.println("指令编号:" + bytesToHexFun2(format.getInstruction()));
		System.out.println("CHECKSUM:" + new U16(bytesToHexFun2(format.getChecksum())).toU10());
		System.out.println("ETX:" + new U16(bytesToHexFun2(format.getEtx())).toU10());

		for (Param p : parsing(format.getBody(), new ArrayList<Param>())) {
			System.out.println("参数序号:" + new U16(bytesToHexFun2(p.getParamNum())).toU10());
			System.out.println("参数长度:" + new U16(bytesToHexFun2(p.getParamLenth())).toU10());
			System.out.println("参数值:" + new U16(bytesToHexFun2(p.getParamValue())).toU10());
			System.out.println("------------------------------------------");
		}
		System.out.println("###########################################");
	}

	public static List<Param> parsing(byte[] datas, List<Param> params) {
		if (datas.length == 0) {
			return params;
		}

		Param param = new Param();
		{
			param.setParamNum(subBytes(datas, 0, param.getParamNum().length));
			param.setParamLenth(subBytes(datas, param.getParamNum().length, param.getParamLenth().length));
			param.setParamValue(subBytes(datas, param.getParamNum().length + param.getParamLenth().length, new U16(bytesToHexFun2(param.getParamLenth())).toU10()));
		}
		params.add(param);

		int length = param.getParamNum().length + param.getParamLenth().length + param.getParamValue().length;

		byte[] newDatas = subBytes(datas, length, datas.length - length);
		return parsing(newDatas, params);
	}

	public static byte[] subBytes(byte[] src, int begin, int count) {
		byte[] bs = new byte[count];
		System.arraycopy(src, begin, bs, 0, count);
		return bs;
	}

	private static final char[] HEX_CHAR = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

	/**
	 * 方法二： byte[] to hex string
	 * 
	 * @param bytes
	 * @return
	 */
	static public String bytesToHexFun2(byte[] bytes) {
		char[] buf = new char[bytes.length * 2];
		int index = 0;
		for (byte b : bytes) { // 利用位运算进行转换，可以看作方法一的变种
			buf[index++] = HEX_CHAR[b >>> 4 & 0xf];
			buf[index++] = HEX_CHAR[b & 0xf];
		}

		return new String(buf);
	}

	/**
	 * 将16进制字符串转换为byte[]
	 * 
	 * @param str
	 * @return
	 */
	public static byte[] toBytes(String str) {
		if (str == null || str.trim().equals("")) {
			return new byte[0];
		}

		byte[] bytes = new byte[str.length() / 2];
		for (int i = 0; i < str.length() / 2; i++) {
			String subStr = str.substring(i * 2, i * 2 + 2);
			bytes[i] = (byte) Integer.parseInt(subStr, 16);
		}

		return bytes;
	}

}

class DataFormat {

	private byte[] stx = new byte[2];

	private byte[] length = new byte[2];

	private byte[] instruction = new byte[1];

	@SuppressWarnings("unused")
	private byte[] body;

	private byte[] checksum = new byte[1];

	private byte[] etx = new byte[1];

	private byte[] datas;

	public DataFormat(byte[] datas) {
		this.datas = datas;
	}

	public byte[] getStx() {
		return this.subBytes(datas, 0, this.stx.length);
	}

	public byte[] getLength() {
		byte[] bys = this.subBytes(datas, this.stx.length, this.length.length);

		{// 大端小端的区别，值为整个帧数据长度，包括 STX 及 ETX，低字节在前
			byte tmp = bys[0];
			bys[0] = bys[1];
			bys[1] = tmp;
		}

		return bys;
	}

	public byte[] getInstruction() {
		return this.subBytes(datas, this.stx.length + this.stx.length, this.instruction.length);
	}

	public byte[] getBody() {
		int start = (this.stx.length + this.stx.length + this.instruction.length);
		int end = this.etx.length + this.checksum.length;

		return this.subBytes(datas, start, datas.length - ( start + end ));
	}

	public byte[] getChecksum() {
		return this.subBytes(datas, datas.length - (this.etx.length + this.checksum.length), this.checksum.length);
	}

	public byte[] getEtx() {
		return this.subBytes(datas, datas.length - this.etx.length, this.etx.length);
	}

	// public void parsing(byte[] datas) {
	// this.stx = this.subBytes(datas, 0, this.stx.length);
	// this.length = this.subBytes(datas, this.stx.length, this.length.length);
	// this.instruction = this.subBytes(datas, this.stx.length + this.stx.length,
	// this.instruction.length);
	//
	// int start = (this.stx.length + this.stx.length + this.instruction.length);
	// int end = this.etx.length + this.checksum.length;
	//
	// this.body = this.subBytes(datas, start, datas.length - (start + end - 1));
	//
	// this.checksum = this.subBytes(datas, datas.length - (this.etx.length +
	// this.checksum.length), this.checksum.length);
	// this.etx = this.subBytes(datas, datas.length - this.etx.length,
	// this.etx.length);
	// }

	public byte[] subBytes(byte[] src, int begin, int count) {
		byte[] bs = new byte[count];
		System.arraycopy(src, begin, bs, 0, count);
		return bs;
	}
}

@Data
class Param {

	private byte[] paramNum = new byte[1];

	private byte[] paramLenth = new byte[1];

	private byte[] paramValue;

}
